
<Serializable()> Friend Class Table
    Private m_address As Integer = 0
    Private m_width As Short = 0
    Private m_height As Short = 0
    Private m_byteSize As Byte = 1
    Private m_name As String = ""
    Private m_description As BikDescription = Nothing

    Private m_multiplier As Double = 1
    Private m_preDivider As Double = 0
    Private m_offset As Double = 0
    Private m_marginal As Byte = 0
    Private m_trim As Short = 0
    Private m_Importable As Boolean = False

    Private m_axisSwap As Boolean = False
    Private m_widthInvert As Boolean = False
    Private m_heightInvert As Boolean = False
    Private m_dispMode As DisplayMode = DisplayMode.BK_DISP_RAW
    Private m_dispScheme As DisplayScheme = DisplayScheme.BK_SCH_BYTE

    Private m_widthAxis As Scale = Nothing
    Private m_heightAxis As Scale = Nothing
    <NonSerialized()> Private m_tableCont As TableCont = Nothing
    Private m_emulatorAble As Boolean = False

    <NonSerialized()> Private m_Vars As Vars = Nothing

    Private m_next As Table = Nothing
    <NonSerialized()> Private m_mirrorable As Boolean = False

    Friend Sub New(ByVal name_ As String)
        m_name = name_
        m_widthAxis = New Scale(-1, 1, 0, 0, Nothing)
        m_heightAxis = New Scale(-1, 1, 0, 0, Nothing)
    End Sub
    Friend Sub New(ByVal Address_ As Integer, ByVal width_ As Short, ByVal height_ As Short, ByVal name_ As String)
        m_address = Address_
        m_width = width_
        m_height = height_
        m_byteSize = 1
        m_name = Trim(name_)
        m_widthAxis = New Scale(-1, 1, 0, 0, Nothing)
        m_heightAxis = New Scale(-1, 1, 0, 0, Nothing)
    End Sub
    Friend Sub New(ByVal Address_ As Integer, ByVal width_ As Short, ByVal height_ As Short, ByVal name_ As String, ByVal ByteSize As Byte)
        m_address = Address_
        m_width = width_
        m_height = height_
        m_name = Trim(name_)
        m_byteSize = ByteSize
        m_widthAxis = New Scale(0, 1, 0, 0, Nothing)
        m_heightAxis = New Scale(0, 1, 0, 0, Nothing)
    End Sub
    Friend Sub addNode(ByRef node As Table)
        If IsNothing(m_next) Then
            If node.Address() <> m_address Or node.Address = -1 Then
                m_next = node
            End If
        Else
            If node.Address() <> m_address Or node.Address = -1 Then
                m_next.addNode(node)
            End If
        End If
    End Sub
    Friend Sub addToCont(ByRef node As Table)
        If IsNothing(m_tableCont) Then m_tableCont = New TableCont("Scales")
        m_tableCont.addTable(node)
    End Sub
    Friend Sub setDisplay(ByVal Multiplier As Double, ByVal preDivider As Double, ByVal offset As Double, ByVal marginal As Byte)
        m_multiplier = Multiplier
        m_preDivider = preDivider
        m_offset = offset
        m_marginal = marginal
    End Sub
    Friend Sub setAxis(ByVal AxisSwap As Boolean, ByVal WidthInvert As Boolean, ByVal HeightInvert As Boolean, ByVal DisplayMode As DisplayMode, ByVal DisplayScheme As DisplayScheme)
        m_axisSwap = AxisSwap
        m_widthInvert = WidthInvert
        m_heightInvert = HeightInvert
        m_dispMode = DisplayMode
        m_dispScheme = DisplayScheme
    End Sub
    Friend Sub setWidthAxis(ByRef axis As Scale)
        m_widthAxis = axis
    End Sub
    Friend Sub setHeightAxis(ByRef axis As Scale)
        m_heightAxis = axis
    End Sub

    Friend ReadOnly Property Value() As Double
        Get
            Dim tm_value As Double = 1
            If m_preDivider <> 0 Then tm_value = m_preDivider / tm_value
            tm_value *= m_multiplier
            Return tm_value
        End Get
    End Property
    Friend Property Variables() As Vars
        Get
            Return m_Vars
        End Get
        Set(ByVal value As Vars)
            m_Vars = value
        End Set
    End Property
    Friend Function getCont() As TableCont
        Return m_tableCont
    End Function
    Public Property Address() As Integer
        Get
            Return m_address
        End Get
        Set(ByVal value As Integer)
            m_address = value
        End Set
    End Property
    Public Property Name() As String
        Get
            Return m_name
        End Get
        Set(ByVal value As String)
            m_name = value
        End Set
    End Property
    Public Property Importable() As Boolean
        Get
            Return m_Importable
        End Get
        Set(ByVal value As Boolean)
            m_Importable = value
        End Set
    End Property
    Public Property Height() As Short
        Get
            Return m_height
        End Get
        Set(ByVal value As Short)
            m_height = value
        End Set
    End Property
    Friend ReadOnly Property adjustedHeight() As Integer
        Get
            If m_axisSwap Then Return m_width Else Return m_height
        End Get
    End Property
    Public Property Width() As Short
        Get
            Return m_width
        End Get
        Set(ByVal value As Short)
            m_width = value
        End Set
    End Property
    Friend ReadOnly Property AdjustedWidth() As Integer
        Get
            If m_axisSwap Then Return m_height Else Return m_width
        End Get
    End Property
    Public Property ByteSize() As Byte
        Get
            Return m_byteSize
        End Get
        Set(ByVal value As Byte)
            m_byteSize = value
        End Set
    End Property
    Public Property Multiplier() As Double
        Get
            Return m_multiplier
        End Get
        Set(ByVal value As Double)
            m_multiplier = value
        End Set
    End Property
    Public Property preDivider() As Double
        Get
            Return m_preDivider
        End Get
        Set(ByVal value As Double)
            m_preDivider = value
        End Set
    End Property
    Public Property Offset() As Double
        Get
            Return m_offset
        End Get
        Set(ByVal value As Double)
            m_offset = value
        End Set
    End Property
    Public Property Mirrorable() As Boolean
        Get
            Return m_mirrorable
        End Get
        Set(ByVal value As Boolean)
            m_mirrorable = value
        End Set
    End Property
    ''' <summary>
    ''' Length in physical bytes of the table
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Friend ReadOnly Property Length() As Integer
        Get
            Return m_width * m_height * m_byteSize
        End Get
    End Property
    Public Property Scheme() As DisplayScheme
        Get
            Return m_dispScheme
        End Get
        Set(ByVal value As DisplayScheme)
            m_dispScheme = value
        End Set
    End Property
    Public Property Mode() As DisplayMode
        Get
            Return m_dispMode
        End Get
        Set(ByVal value As DisplayMode)
            m_dispMode = value
        End Set
    End Property
    Public Property mTrim() As Integer
        Get
            Return m_trim
        End Get
        Set(ByVal value As Integer)
            m_trim = value
        End Set
    End Property
    Public Property Description() As BikDescription
        Get
            Return m_description
        End Get
        Set(ByVal value As BikDescription)
            m_description = value
        End Set
    End Property
    Public Property EmulatorAble() As Boolean
        Get
            Return m_emulatorAble
        End Get
        Set(ByVal value As Boolean)
            m_emulatorAble = value
        End Set
    End Property
    Public Property TableVars() As Vars
        Get
            Return m_Vars
        End Get
        Set(ByVal value As Vars)
            m_Vars = value
        End Set
    End Property

    Friend ReadOnly Property Max() As Double
        Get
            Select Case m_byteSize
                Case 1
                    Select Case m_dispScheme
                        Case DisplayScheme.BK_SCH_EARLY
                            Return 200
                        Case DisplayScheme.BK_SCH_LATE
                            Return 200
                        Case DisplayScheme.BK_SCH_IGN
                            Return 60
                        Case DisplayScheme.BK_SCH_BYTE
                            Return 255 * m_multiplier + m_offset
                        Case DisplayScheme.BK_SCH_SINGLE
                            Return Single.MaxValue
                    End Select
                Case 2
                    Return (65535 * m_multiplier) + m_offset
            End Select
        End Get
    End Property
    Friend ReadOnly Property Min() As Double
        Get
            Select Case m_byteSize
                Case 1
                    Select Case m_dispScheme
                        Case DisplayScheme.BK_SCH_EARLY
                            Return 50
                        Case DisplayScheme.BK_SCH_LATE
                            Return 100
                        Case DisplayScheme.BK_SCH_IGN
                            Return 0
                        Case DisplayScheme.BK_SCH_BYTE
                            Return m_offset
                        Case DisplayScheme.BK_SCH_SINGLE
                            Return Single.MinValue
                    End Select
                Case 2
                    Return m_offset
            End Select
        End Get
    End Property
    Friend ReadOnly Property AxisSwap() As Boolean
        Get
            Return m_axisSwap
        End Get
    End Property
    ''' <summary>
    ''' Unadjusted Invert (bool) of the real width axis
    ''' </summary>
    Friend ReadOnly Property WidthInvert() As Boolean
        Get
            Return m_widthInvert
        End Get
    End Property
    Friend ReadOnly Property WidthInvertDisplay() As Boolean
        Get
            If m_axisSwap Then Return m_heightInvert Else Return m_widthInvert
        End Get
    End Property
    ''' <summary>
    ''' Unadjusted Invert (bool) of the real Height Axis
    ''' </summary>
    Friend ReadOnly Property HeightInvert() As Boolean
        Get
            Return m_heightInvert
        End Get
    End Property
    Friend ReadOnly Property HeightInvertDisplay() As Boolean
        Get
            If m_axisSwap Then Return m_widthInvert Else Return m_heightInvert
        End Get
    End Property

    Friend Function compare(ByRef map1 As Table, ByRef map2 As Table) As Integer
        If Not IsNothing(map1) And Not IsNothing(map2) Then
            If map1.Width = map2.Width And map1.Height = map2.Height And map1.ByteSize = map2.ByteSize Then
                Return 0
            ElseIf map1.Length <= map2.Length Then
                Return -1
            Else
                Return 1
            End If
        End If
    End Function
    Shared Operator =(ByVal map1 As Table, ByVal map2 As Table) As Boolean
        If map1.Width = map2.Width And map1.Height = map2.Height And map1.ByteSize = map2.ByteSize Then
            Return True
        Else
            Return False
        End If
    End Operator
    Shared Operator <>(ByVal map1 As Table, ByVal map2 As Table) As Boolean
        If map1.Width = map2.Width And map1.Height = map2.Height And map1.ByteSize = map2.ByteSize Then
            Return False
        Else
            Return True
        End If
    End Operator

    Friend Function count() As Integer
        Dim intReturn As Integer = 1
        If (Not IsNothing(m_next)) Then
            intReturn += m_next.count
        End If
        If Not IsNothing(m_tableCont) Then
            intReturn += m_tableCont.countTables
        End If
        Return (intReturn)
    End Function
    Friend Function lengthTotal() As Integer
        Dim intReturn As Integer
        intReturn = m_width * m_height * m_byteSize

        If (Not IsNothing(m_next)) Then
            intReturn = intReturn + m_next.lengthTotal
        End If

        Return (intReturn)
    End Function

    Friend Function getRaw(ByRef Array() As Byte) As Byte()
        Dim f_array() As Byte = Nothing
        If Not IsNothing(Array) Then
            If m_multiplier = 0 Then m_multiplier = 1
            If m_address <> 0 And UBound(Array) >= (m_address + Me.Length) Then
                ReDim f_array(0 To (Me.Length - 1))
                array_copy(Array, m_address, f_array, 0, Me.Length)
            End If
        End If
        Return f_array
    End Function
    Friend Sub setRaw(ByRef Array() As Byte, ByRef setArray() As Byte)
        If Not IsNothing(Array) And Not IsNothing(setArray) Then
            If m_address <> 0 And (UBound(setArray) - LBound(setArray) + 1) = Me.Length And _
            UBound(Array) >= (m_address + Me.Length) Then
                array_copy(setArray, 0, Array, m_address, Me.Length)
            End If
        End If
    End Sub

   
   
    Friend Function getTable(ByRef Array() As Byte) As Single(,)
        If Not IsNothing(Array) Then
            Dim f_grid As Single(,) = Nothing

            Dim tm_width As Short = Me.Width
            Dim tm_height As Short = Me.Height

            If Me.m_axisSwap Then
                tm_width = Me.Height
                tm_height = Me.Width
            End If
            ReDim f_grid(tm_width, tm_height)
            Dim tm_x As Short
            Dim tm_y As Short
            Dim tm_value As Double

            For x As Short = 0 To Me.Width - 1
                For y As Short = 0 To Me.Height - 1
                    If Me.ByteSize = 1 Then
                        tm_value = Array(m_address + (y * Me.Width) + x) - Me.m_trim
                    Else
                        tm_value = MAKEWORD(Array(m_address + (y * Me.Width * Me.ByteSize) + (x * Me.ByteSize)) _
                        , Array(m_address + 1 + (y * Me.Width * Me.ByteSize) + (x * Me.ByteSize))) - Me.m_trim
                    End If
                    Select Case (Me.Scheme)
                        Case DisplayScheme.BK_SCH_IGN
                            If Not tm_value < 128 Then
                                tm_value -= 128
                            End If
                        Case DisplayScheme.BK_SCH_EARLY
                            If Not tm_value < 128 Then
                                tm_value -= 192
                            End If
                    End Select
                    If m_preDivider <> 0 Then tm_value = m_preDivider / tm_value
                    tm_value *= m_multiplier
                    tm_value += m_offset
                    tm_y = y
                    tm_x = x
                    If m_heightInvert Then tm_y = Me.Height - 1 - y
                    If m_widthInvert Then tm_x = Me.Width - 1 - x
                    If m_axisSwap Then Swap(tm_x, tm_y)
                    f_grid(tm_x, tm_y) = tm_value
                Next
            Next
            Return f_grid
        Else
            Return Nothing
        End If
    End Function
    
    Friend Function getValue(ByRef Array As Byte(), ByVal offset As Integer) As Object
        Dim f_return As Integer = 0
        If Not IsNothing(Array) Then
            If offset >= Me.Width * Me.Height Then offset = Me.Width * Me.Height - 1
            If UBound(Array) >= Me.Address + Me.Length Then
                Select Case Me.ByteSize
                    Case 1
                        Return Array(Me.Address + offset)
                    Case 2
                        Return MAKEWORD(Array(1 + Me.Address + offset * 2), Array(Me.Address + offset * 2))
                    Case 4
                        Return System.BitConverter.ToSingle(Array, Address + (4 * offset))
                End Select
            End If
        End If
        Return f_return
    End Function
    Friend Sub setValue(ByRef Array As Byte(), ByVal offset As Integer, ByVal Val As Object)
        If Not IsNothing(Array) Then
            If offset >= Me.Width * Me.Height Then offset = Me.Width * Me.Height - 1
            If UBound(Array) >= Me.Address + Me.Length Then
                Select Case Me.ByteSize
                    Case 1
                        Array(Me.Address + offset) = CByte(Val)
                    Case 2
                        System.Array.Copy(New Byte() {HIBYTE(Val), LOBYTE(Val)}, 0, Array, Address + (offset * 2), 2)
                    Case 4
                        System.Array.Copy(System.BitConverter.GetBytes(CSng(Val)), 0, Array, Address + (4 * offset), 4)
                End Select
            End If
        End If
    End Sub

    Friend Function getWidthDisplay(ByRef array() As Byte) As String()
        Dim f_return() As String = Nothing
        If m_axisSwap Then
            ' Swap Axis, width is now really the height
            Dim f_min As Var = m_heightAxis.minVar
            Dim f_max As Var = m_heightAxis.maxVar
            If Not IsNothing(m_heightAxis.Overlay) Or m_heightAxis.Address >= 0 Or (Not IsNothing(f_min) And Not IsNothing(f_max)) Then
                If Not IsNothing(f_min) And Not IsNothing(f_max) And Me.Height >= 1 Then
                    Dim f_str(Me.Height - 1) As String
                    Dim nMax As Single = f_max.getValue(array)
                    Dim nMin As Single = f_min.getValue(array)
                    If nMin = Single.NaN Or nMax = Single.NaN Or nMin = Single.NegativeInfinity Or nMax = Single.PositiveInfinity Then
                        nMax = 0
                        nMin = 0
                    Else
                        Dim f_split As Double = (f_max.getValue(array) - f_min.getValue(array)) / Me.Height - 1
                        For i As Int16 = 0 To Me.Height - 1
                            f_str(i) = Str((f_min.getValue(array) + (i * f_split)) \ 1)
                        Next
                        m_heightAxis.Overlay = f_str
                    End If
                End If
                    If Not IsNothing(m_heightAxis.Overlay) Then
                        f_return = m_heightAxis.Overlay
                    ElseIf UBound(array) >= m_heightAxis.Address + Me.Height Then
                        ReDim f_return(Me.Height - 1)
                        Dim tm_value As Double
                        For i As Short = 0 To UBound(f_return)
                            tm_value = array(m_heightAxis.Address + i)
                            If m_heightAxis.preDivider <> 0 Then tm_value = m_heightAxis.preDivider / tm_value
                            f_return(i) = (tm_value * m_heightAxis.Multiplier) + m_heightAxis.Offset
                        Next
                        If m_heightInvert Then
                            Dim f_tmp(Me.Height - 1) As String
                            f_return = Reverse(f_return)
                        End If
                    End If
                ElseIf m_heightAxis.Address = -1 Then
                    ReDim f_return(Me.Height - 1)
                    For i As Short = 0 To UBound(f_return)
                        f_return(i) = Str(i)
                    Next
                End If
        Else
            ' width is normal
            Dim f_min As Var = m_widthAxis.minVar
            Dim f_max As Var = m_widthAxis.maxVar
            If Not IsNothing(m_widthAxis.Overlay) Or m_widthAxis.Address >= 0 Or (Not IsNothing(f_min) And Not IsNothing(f_max)) Then
                If Not IsNothing(f_min) And Not IsNothing(f_max) And Me.Width >= 1 Then
                    Dim f_str(Me.Width - 1) As String
                    Dim f_split As Double = (f_max.getValue(array) - f_min.getValue(array)) / (Me.Width - 1)
                    For i As Int16 = 0 To Me.Width - 1
                        f_str(i) = Str((f_min.getValue(array) + (i * f_split)) \ 1)
                    Next
                    m_widthAxis.Overlay = f_str
                End If
                If Not IsNothing(m_widthAxis.Overlay) Then
                    f_return = m_widthAxis.Overlay
                ElseIf UBound(array) >= m_widthAxis.Address + Me.Width Then
                    ReDim f_return(Me.Width - 1)
                    Dim tm_value As Double
                    For i As Short = 0 To UBound(f_return)
                        tm_value = array(m_widthAxis.Address + i)
                        If m_widthAxis.preDivider <> 0 Then tm_value = m_widthAxis.preDivider / tm_value
                        f_return(i) = (tm_value * m_widthAxis.Multiplier) + m_widthAxis.Offset
                    Next
                    If m_widthInvert Then
                        Dim f_tmp(Me.Width - 1) As String
                        f_return = Reverse(f_return)
                    End If
                End If
            ElseIf m_widthAxis.Address = -1 Then
                ReDim f_return(Me.Width - 1)
                For i As Short = 0 To UBound(f_return)
                    f_return(i) = Str(i)
                Next
            End If
        End If
        Return f_return
    End Function
    Friend Function getScaleValues(ByRef array As Byte(), ByVal Height As Boolean, ByVal real As Boolean) As Single()
        Dim ptScale As Scale
        Dim intLength As Integer
        Dim invert As Boolean
        If Not Height Then
            If real Then
                ptScale = Me.m_widthAxis
                intLength = Me.m_width
                invert = Me.m_widthInvert
            Else
                ptScale = Me.getWidthScale
                intLength = Me.Width
                invert = WidthInvert
            End If
        Else
            If real Then
                ptScale = Me.m_heightAxis
                intLength = Me.m_height
                invert = m_heightInvert
            Else
                ptScale = Me.getHeightScale
                intLength = Me.Height
                invert = HeightInvert
            End If
        End If
        If real Or Not invert Then
            Return ptScale.getValues(array, intLength)
        Else
            Dim sngInvert() As Single = ptScale.getValues(array, intLength)
            For i As Integer = 0 To UBound(sngInvert)
                sngInvert(i) *= -1
            Next
            Return sngInvert
        End If
    End Function
    Friend Function getWidthCalc(ByRef Array As Byte()) As Single()
        Dim f_return() As Single = Nothing
        Dim f_val As Integer = 0
        If m_axisSwap Then
            If m_heightAxis.Address >= 0 Then
                If UBound(Array) >= m_heightAxis.Address + Me.Height Then
                    ReDim f_return(Me.Height - 1)
                    For i As Int16 = 0 To Me.Height - 1
                        f_return(i) = Array(m_heightAxis.Address + i)
                    Next
                End If
            Else
                f_val = Me.Height
                GoTo Past
            End If
        Else
            If m_widthAxis.Address >= 0 Then
                If UBound(Array) >= m_widthAxis.Address + Me.Width Then
                    ReDim f_return(Me.Width - 1)
                    For i As Int16 = 0 To Me.Width - 1
                        f_return(i) = Array(m_widthAxis.Address + i)
                    Next
                End If
            Else
                f_val = Me.Width
                GoTo Past
            End If
        End If

        Return f_return
        Exit Function
Past:
        ReDim f_return(f_val - 1)
        For i As Int16 = 0 To f_val - 1
            f_return(i) = i
        Next
        Return f_return
    End Function
    Friend Function getHeightDisplay(ByRef Array As Byte()) As String()
        Dim f_return() As String = Nothing
        ' Swap Axis, width is now really the height
        If Not m_axisSwap Then
            If Not IsNothing(m_heightAxis.Overlay) Or m_heightAxis.Address >= 0 Then
                Dim f_min As Var = m_heightAxis.minVar
                Dim f_max As Var = m_heightAxis.maxVar
                If Not IsNothing(f_min) And Not IsNothing(f_max) And Me.Height >= 1 Then
                    Dim f_str(Me.Height - 1) As String
                    Dim nMax As Single = f_max.getValue(Array)
                    Dim nMin As Single = f_min.getValue(Array)
                    If nMin = Single.NaN Or nMax = Single.NaN Or nMin = Single.NegativeInfinity Or nMax = Single.PositiveInfinity Then
                        nMax = 0
                        nMin = 0
                    Else
                        Dim f_split As Double = (f_max.getValue(Array) - f_min.getValue(Array)) / Me.Height - 1
                        For i As Int16 = 0 To Me.Height - 1
                            f_str(i) = Str((f_min.getValue(Array) + (i * f_split)) \ 1)
                        Next
                        m_heightAxis.Overlay = f_str
                    End If
                End If
                If Not IsNothing(m_heightAxis.Overlay) Then
                    f_return = m_heightAxis.Overlay
                ElseIf UBound(Array) >= m_heightAxis.Address + Me.Height Then
                    ReDim f_return(Me.Height - 1)
                    Dim tm_value As Double
                    For i As Short = 0 To UBound(f_return)
                        tm_value = Array(m_heightAxis.Address + i)
                        If m_heightAxis.preDivider <> 0 Then tm_value = m_heightAxis.preDivider / tm_value
                        f_return(i) = (tm_value * m_heightAxis.Multiplier) + m_heightAxis.Offset
                    Next
                    If m_heightInvert Then
                        Dim f_tmp(Me.Height - 1) As String
                        f_return = Reverse(f_return)
                    End If
                End If
            ElseIf m_heightAxis.Address = -1 Then
                ReDim f_return(Me.Height - 1)
                For i As Short = 0 To UBound(f_return)
                    f_return(i) = Str(i)
                Next
            End If
        Else
            ' width is normal
            If Not IsNothing(m_widthAxis.Overlay) Or m_widthAxis.Address >= 0 Then
                Dim f_min As Var = m_widthAxis.minVar
                Dim f_max As Var = m_widthAxis.maxVar
                If Not IsNothing(f_min) And Not IsNothing(f_max) And Me.Width >= 1 Then
                    Dim f_str(Me.Width - 1) As String
                    Dim f_split As Double = (f_max.getValue(Array) - f_min.getValue(Array)) / Me.Width - 1
                    For i As Int16 = 0 To Me.Width - 1
                        f_str(i) = Str((f_min.getValue(Array) + (i * f_split)) \ 1)
                    Next
                    m_widthAxis.Overlay = f_str
                End If
                If Not IsNothing(m_widthAxis.Overlay) Then
                    f_return = m_widthAxis.Overlay
                ElseIf UBound(Array) >= m_widthAxis.Address + Me.Width Then
                    ReDim f_return(Me.Width - 1)
                    Dim tm_value As Double
                    For i As Short = 0 To UBound(f_return)
                        tm_value = Array(m_widthAxis.Address + i)
                        If m_widthAxis.preDivider <> 0 Then tm_value = m_widthAxis.preDivider / tm_value
                        f_return(i) = (tm_value * m_widthAxis.Multiplier) + m_widthAxis.Offset
                    Next
                    If m_widthInvert Then
                        Dim f_tmp(Me.Width - 1) As String
                        f_return = Reverse(f_return)
                    End If
                End If
            ElseIf m_widthAxis.Address = -1 Then
                ReDim f_return(Me.Width - 1)
                For i As Short = 0 To UBound(f_return)
                    f_return(i) = Str(i)
                Next
            End If
        End If
        Return f_return
    End Function
    Friend Function getHeightCalc(ByRef Array As Byte()) As Single()
        Dim f_return() As Single = Nothing
        Dim f_val As Integer = 0
        If Not m_axisSwap Then
            If m_heightAxis.Address >= 0 Then
                If UBound(Array) >= m_heightAxis.Address + Me.Height Then
                    ReDim f_return(Me.Height - 1)
                    For i As Int16 = 0 To Me.Height - 1
                        f_return(i) = Array(m_heightAxis.Address + i)
                    Next
                End If
            Else
                f_val = Me.Height
                GoTo Past
            End If
        Else
            If m_widthAxis.Address >= 0 Then
                If UBound(Array) >= m_widthAxis.Address + Me.Width Then
                    ReDim f_return(Me.Width - 1)
                    For i As Int16 = 0 To Me.Width - 1
                        f_return(i) = Array(m_widthAxis.Address + i)
                    Next
                End If
            Else
                f_val = Me.Width
                GoTo Past
            End If
        End If

        Return f_return
        Exit Function
Past:
        ReDim f_return(f_val - 1)
        For i As Int16 = 0 To f_val - 1
            f_return(i) = i
        Next
        Return f_return
    End Function
    ''' <summary>
    ''' Gets the Displayed Width scale
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Friend Function getWidthScale() As Scale
        If m_axisSwap Then Return m_heightAxis Else Return m_widthAxis
    End Function
    Friend Function getHeightScale() As Scale
        If m_axisSwap Then Return m_widthAxis Else Return m_heightAxis
    End Function

    Friend Sub setNext(ByRef nextNode_ As Table)
        m_next = nextNode_
    End Sub
    Friend Function getNext() As Table
        Return m_next
    End Function

    Private Sub Invert(ByRef array() As Integer)
        Dim f_max As Byte = 0
        For i As Int16 = 0 To UBound(array)
            If array(i) > f_max Then f_max = array(i)
        Next
        For i As Int16 = 0 To UBound(array)
            array(i) -= f_max
            array(i) *= -1
        Next
    End Sub
    Private Sub graphFilter(ByRef array(,) As Integer, ByVal Eight As Boolean, ByVal Seven As Boolean)
        For x As Integer = 0 To array.GetUpperBound(0)
            For y As Integer = 0 To array.GetUpperBound(1)
                If Seven Then
                    If array(x, y) >= 128 Then
                        array(x, y) = ((array(x, y) - 192) / 128) * 255
                        'BitClear(array(x, y), 6)
                    End If
                ElseIf Eight Then
                    If array(x, y) <= 255 Then If BitIsSet(array(x, y), 7) Then BitClear(array(x, y), 7)
                End If
            Next
        Next
    End Sub
  
    Friend ReadOnly Property widthEditable() As Boolean
        Get
            If Not IsNothing(Me.getWidthScale) Then
                If Me.getWidthScale.Address >= 0 Then : Return True
                ElseIf Not IsNothing(Me.getWidthScale.minVar) And Not IsNothing(Me.getWidthScale.maxVar) Then : Return True : Else : Return False
                End If
            Else : Return False
            End If
        End Get
    End Property
    Friend ReadOnly Property heightEditable() As Boolean
        Get
            If Not IsNothing(Me.getHeightScale) Then
                If Me.getWidthScale.Address >= 0 Then : Return True
                ElseIf Not IsNothing(Me.getHeightScale.minVar) And Not IsNothing(Me.getHeightScale.maxVar) Then : Return True : Else : Return False
                End If
            Else : Return False
            End If
        End Get
    End Property

    ''' <summary>
    ''' Finds the nearest datalogging point to the current cell.
    ''' </summary>
    ''' <param name="log"></param>
    ''' <returns></returns>
    ''' <remarks>Table must have a valid width and height scale. of tracable values</remarks>
    Friend Function traceFindNearestPoint(ByRef Array_ As Byte(), ByRef log As DataLogging.ConsultLog, ByVal pt As PointF) As Long
        If Not IsNothing(m_widthAxis) And Not IsNothing(m_heightAxis) Then
            Dim f_Min As Double = 512
            Dim f_MinIndex As UInt32 = 0
            Dim f_arr As Double
            Dim f_point As PointF
            Dim f_result As PointF

            For i As Integer = log.Count - 1 To 0 Step -1
                f_point.X = traceWidth(Array_, log(i))
                f_point.Y = traceHeight(Array_, log(i))
                If f_point.X <> -1 And f_point.Y <> -1 Then
                    f_result.X = pt.X - f_point.X
                    f_result.Y = pt.Y - f_point.Y
                    f_arr = Math.Sqrt((f_result.X * f_result.X) + (f_result.Y * f_result.Y))
                    If f_arr < f_Min Then
                        f_Min = f_arr
                        f_MinIndex = i
                    End If
                End If
            Next
            Return f_MinIndex
        Else
            Return -1
        End If
    End Function

    Friend Function traceWidth(ByRef Array As Byte(), ByRef stream As Consult_Args) As Double
        Try
            Dim f_return As Double = 0
            Dim f_scale As String() = Me.getWidthDisplay(Array)
            Dim f_value As Double = 0
            If Not IsNothing(f_scale) Then
                If UBound(f_scale) + 1 = Me.AdjustedWidth Then
                    Try
                        f_value = stream(Me.getWidthScale.Trace)

                        Dim f_useScale(UBound(f_scale)) As Double
                        For i As Int16 = 0 To UBound(f_scale)
                            f_useScale(i) = Val(f_scale(i))
                        Next
                        If f_useScale(UBound(f_useScale)) > f_useScale(0) Then '' If its an Upward slope
                            For i As Int16 = 0 To Me.AdjustedWidth - 1
                                f_return = i
                                If f_value < f_useScale(i) Then
                                    If i = 0 Then Exit For
                                    Dim f_diff As Double = f_useScale(i) - f_useScale(i - 1)
                                    Dim f_split As Double = (f_value - f_useScale(i - 1)) / f_diff
                                    f_return = i + f_split - 1
                                    Exit For
                                End If
                            Next
                        Else '' If its a Downward slope
                            For i As Int16 = 0 To Me.AdjustedWidth - 1
                                f_return = i
                                If f_value > f_useScale(i) Then
                                    If i = 0 Then Exit For
                                    Dim f_diff As Double = f_useScale(i - 1) - f_useScale(i)
                                    Dim f_split As Double = ((f_value - f_useScale(i)) / f_diff)
                                    f_return = i - f_split
                                    Exit For
                                End If
                            Next
                        End If
                    Catch ex As Exception
                        f_return = 0
                    End Try
                End If
            End If
            If f_return < 0 Then : Return 0 : ElseIf f_return > Me.AdjustedWidth Then : Return Me.AdjustedWidth : Else : Return f_return : End If
        Catch ex As Exception

        End Try
    End Function
    Friend Function traceHeight(ByRef Array As Byte(), ByRef stream As Consult_Args, Optional ByRef Car As CarBase = Nothing) As Double
        Try
            Dim f_return As Double = 0
            Dim f_scale As String() = Me.getHeightDisplay(Array)
            Dim f_value As Double = 0
            If Not IsNothing(f_scale) Then
                If UBound(f_scale) + 1 = Me.adjustedHeight Then
                    Try
                        f_value = stream(Me.getHeightScale.Trace)

                        Dim f_useScale(UBound(f_scale)) As Double
                        For i As Int16 = 0 To UBound(f_scale)
                            f_useScale(i) = Val(f_scale(i))
                        Next
                        If f_useScale(UBound(f_useScale)) > f_useScale(0) Then '' If its an Upward slope
                            For i As Int16 = 0 To Me.adjustedHeight - 1
                                f_return = i
                                If f_value < f_useScale(i) Then
                                    If i = 0 Then Exit For
                                    Dim f_diff As Double = f_useScale(i) - f_useScale(i - 1)
                                    Dim f_split As Double = (f_value - f_useScale(i - 1)) / f_diff
                                    f_return = i + f_split - 1
                                    Exit For
                                End If
                            Next
                        Else '' If its a Downward slope
                            For i As Int16 = 0 To Me.adjustedHeight - 1
                                f_return = i
                                If f_value > f_useScale(i) Then
                                    If i = 0 Then Exit For
                                    Dim f_diff As Double = f_useScale(i - 1) - f_useScale(i)
                                    Dim f_split As Double = ((f_value - f_useScale(i)) / f_diff)
                                    f_return = i - f_split
                                    Exit For
                                End If
                            Next
                        End If
                    Catch
                        f_return = 0
                    End Try
                End If
            End If
close:
            If f_return < 0 Then : Return 0 : ElseIf f_return > Me.adjustedHeight Then : Return Me.adjustedHeight : Else : Return f_return : End If
        Catch ex As Exception

        End Try
    End Function
    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    ' Interpolation Functions
    Friend Function interNewScale(ByRef ArrBinary() As Byte, ByRef ArrScale() As Byte, ByVal iScale As Scale) As Boolean
        If (Not IsNothing(ArrBinary) And Not IsNothing(ArrScale) And Not IsNothing(iScale)) AndAlso _
            ((Not IsNothing(Me.m_widthAxis) AndAlso Me.m_widthAxis = iScale) Or _
            (Not IsNothing(Me.m_heightAxis) AndAlso Me.m_heightAxis = iScale)) _
        Then
            Dim intLength As Integer = 0
            Dim objScale As Scale = Nothing
            Dim iNewWidth() As Byte = Nothing
            Dim iNewHeight() As Byte = Nothing
            Dim iWidth() As Byte = Nothing
            Dim iHeight() As Byte = Nothing

            If m_widthAxis.Address = -1 Then
                iWidth = New Byte() {0, 1, 2}
                iNewWidth = New Byte() {0, 1, 2}
            Else
                iWidth = iCreateAxis(m_widthAxis.getRaw(ArrBinary, m_width), m_width)
            End If
            If m_heightAxis.Address = -1 Then
                iHeight = New Byte() {0, 1, 2}
                iNewHeight = New Byte() {0, 1, 2}
            Else
                iHeight = iCreateAxis(m_heightAxis.getRaw(ArrBinary, m_height), m_height)
            End If
            If iScale = m_widthAxis AndAlso (iScale.Address + m_width) <= UBound(ArrBinary) Then ' True Width Scale
                intLength = m_width
                objScale = m_widthAxis
                iNewWidth = iCreateAxis(ArrScale, m_width)
                If m_heightAxis.Address <> -1 Then iNewHeight = iCreateAxis(m_heightAxis.getRaw(ArrBinary, m_height), m_height)
            ElseIf iScale = m_heightAxis AndAlso (iScale.Address + m_height) <= UBound(ArrBinary) Then ' True Height Scale
                intLength = m_height
                objScale = m_heightAxis
                iNewHeight = iCreateAxis(ArrScale, m_height)
                If m_widthAxis.Address <> -1 Then iNewWidth = iCreateAxis(m_widthAxis.getRaw(ArrBinary, m_width), m_width)
            Else
                Return False
            End If

            ' Do interpolation code here as we now have the scale, length and what needs doing established.
            Dim iDataGrid(,) As Byte = iCreateGrid(Me.getRaw(ArrBinary), m_width, m_height)
            Dim iResultGrid() As Byte = iData(iWidth, iHeight, iNewWidth, iNewHeight, iDataGrid)

            Me.setRaw(ArrBinary, iResultGrid)
            Return True
        Else
            Return False
        End If
    End Function

    Private Function iCreateGrid(ByRef Arra() As Byte, ByVal X As Short, ByVal Y As Short) As Byte(,)
        Dim f As Integer
        Dim i As Integer
        Dim iGrid(,) As Byte
        ReDim iGrid(0 To X + 1, 0 To Y + 1)
        For i = 0 To X - 1
            For f = 0 To Y - 1
                iGrid(i + 1, f + 1) = Arra((f * X) + i)
            Next
        Next
        iGrid(0, 0) = iGrid(1, 1)
        iGrid(X + 1, Y + 1) = iGrid(X, Y)
        iGrid(X + 1, 0) = iGrid(X, 1)
        iGrid(0, Y + 1) = iGrid(1, Y)
        For i = 1 To X
            iGrid(i, 0) = iGrid(i, 1)
            iGrid(i, Y + 1) = iGrid(i, Y)
        Next
        For f = 1 To Y
            iGrid(0, f) = iGrid(1, f)
            iGrid(X + 1, f) = iGrid(X, f)
        Next
        Return iGrid

    End Function
    Private Function iValue(ByRef TP() As Byte, ByRef RPM() As Byte, ByRef vTP As Byte, ByRef vRPM As Byte, ByRef data(,) As Byte) As Byte
        Dim f, i As Byte
        Dim Y, X As Integer
        Dim Xdiff, Ydiff, XstartPt, YstartPt As Double
        Dim sub_data(0 To 1, 0 To 1) As Byte
        Dim sub_pts(0 To 1) As Byte
        Dim iPts(0 To 1) As Byte

        X = 0
        Do While vTP >= TP(X)
            X = X + 1
        Loop
        Xdiff = TP(X) - TP(X - 1)
        XstartPt = vTP - TP(X - 1)
        X = X - 1

        Y = 0
        Do While vRPM >= RPM(Y)
            Y = Y + 1
        Loop
        Ydiff = RPM(Y) - RPM(Y - 1)
        YstartPt = vRPM - RPM(Y - 1)
        Y = Y - 1

        For i = 0 To 1
            For f = 0 To 1
                sub_data(f, i) = data(f + X, i + Y)
            Next
        Next

        If XstartPt > 0 And YstartPt > 0 And XstartPt < Xdiff And YstartPt < Ydiff Then
            iSubValue(sub_data)
        End If

        If YstartPt = 0 And XstartPt = 0 Then
            iValue = sub_data(0, 0)
            Exit Function
        ElseIf YstartPt = 0 Then
            sub_pts(0) = sub_data(0, 0)
            sub_pts(1) = sub_data(1, 0)
            iValue = TwoPtInter(XstartPt, Xdiff, sub_pts)
            Exit Function
        ElseIf XstartPt = 0 Then
            sub_pts(0) = sub_data(0, 0)
            sub_pts(1) = sub_data(0, 1)
            iValue = TwoPtInter(YstartPt, Ydiff, sub_pts)
            Exit Function
        Else
            sub_pts(0) = sub_data(0, 0)
            sub_pts(1) = sub_data(1, 0)
            iPts(0) = TwoPtInter(XstartPt, Xdiff, sub_pts)
            sub_pts(0) = sub_data(0, 1)
            sub_pts(1) = sub_data(1, 1)
            iPts(1) = TwoPtInter(XstartPt, Xdiff, sub_pts)
            iValue = TwoPtInter(YstartPt, Ydiff, iPts)
            Exit Function
        End If
    End Function
    Private Sub iSubValue(ByRef sData(,) As Byte)
        If Me.m_dispScheme = DisplayScheme.BK_SCH_IGN Or Me.m_dispScheme = DisplayScheme.BK_SCH_EARLY Then
            If Not ((sData(0, 0) >= 128 And sData(0, 1) >= 128 And sData(1, 0) >= 128 And sData(1, 1) >= 128) Or _
                 (sData(0, 0) <= 127 And sData(0, 1) <= 127 And sData(1, 0) <= 127 And sData(1, 1) <= 127)) _
            Then
                For i As Byte = 0 To 1
                    For f As Byte = 0 To 1
                        Select Case Me.m_dispScheme
                            Case DisplayScheme.BK_SCH_IGN
                                If sData(f, i) >= 128 Then
                                    sData(f, i) = iByte(sData(f, i) - 128)
                                End If
                            Case DisplayScheme.BK_SCH_EARLY
                                If sData(f, i) >= 128 Then
                                    sData(f, i) = iByte(sData(f, i) - 192)
                                End If
                        End Select
                    Next
                Next
            End If
        End If
    End Sub
    Private Function TwoPtInter(ByRef SplitPt As Double, ByRef Diff As Double, ByRef pts() As Byte) As Byte
        Dim pt As Byte
        Dim ptSet As Byte = 0

        If ((pts(0) < 128 And pts(1) < 128) Or (pts(0) > 127 And pts(1) > 127)) Or _
            (Me.m_dispScheme <> DisplayScheme.BK_SCH_EARLY And Me.m_dispScheme <> DisplayScheme.BK_SCH_IGN) _
        Then
            pt = iByte(CLng((((SplitPt / Diff) * pts(1)) + ((Diff - SplitPt) / Diff) * pts(0))))
        Else
            Select Case Me.m_dispScheme
                Case DisplayScheme.BK_SCH_IGN
                    ptSet = 128
                Case DisplayScheme.BK_SCH_EARLY
                    ptSet = 192
            End Select
            If pts(0) > 128 Then
                pts(0) = iByte(CInt(pts(0)) - ptSet)
                If pts(0) < 0 Then
                    pts(0) = 0
                End If
            End If
            If pts(1) > 128 Then
                pts(1) = iByte(CInt(pts(1)) - ptSet)
                If pts(1) < 0 Then
                    pts(1) = 0
                End If
            End If
            pt = iByte(CLng((((SplitPt / Diff) * pts(1)) + CLng(((Diff - SplitPt) / Diff) * pts(0)))))
        End If
        Return pt
    End Function
    Private Function iData(ByRef TP() As Byte, ByRef RPM() As Byte, ByRef TPnew() As Byte, ByRef RPMnew() As Byte, ByRef data(,) As Byte) As Byte()
        Dim X As Integer
        Dim Y As Integer
        Dim iDataRet() As Byte
        ReDim iDataRet(0 To (UBound(TP) - 1) * (UBound(RPM) - 1) - 1)

        For Y = LBound(RPM) + 1 To UBound(RPM) - 1
            For X = LBound(TP) + 1 To UBound(TP) - 1
                iDataRet(((Y - 1) * (UBound(TP) - 1)) + (X - 1)) = iValue(TP, RPM, TPnew(X), RPMnew(Y), data)
            Next
        Next
        Return iDataRet
    End Function
    Private Function iCreateAxis(ByRef Arra() As Byte, ByVal Length_ As Short) As Byte()
        Dim iAxis(0 To Length_ + 1) As Byte
        For f As Integer = 0 To Length_ - 1
            iAxis(f + 1) = Arra(f)
        Next
        iAxis(0) = 0
        iAxis(17) = 255
        Return iAxis
    End Function
    Private Function gPadArray(ByRef array() As Single) As Single()
        If UBound(array) = 0 Then
            Return New Single() {array(0), array(0)}
        Else
            Return array
        End If
    End Function
End Class
